package player;

import java.awt.Component;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.media.Codec;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.Time;
import javax.media.UnsupportedPlugInException;
import javax.media.control.TrackControl;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.format.VideoFormat;


public class MyProcessor implements ControllerListener, DataSinkListener {
	Processor myProcessor = null;
	java.io.File urlString = null;
	java.net.URL urlSource = null;
	
	private boolean giveVisualComponent = false;
	public MyEffect myEffect;
	public MyBrightness myBrightness;
	
	/**
	 * @author Michael Kascha 0548800
	 * constructor for the processor, depening on the source
	 */
	public MyProcessor(String urlString) {
		// URL Source
		if (urlString.startsWith("http")) {
			try {
				urlSource = new URL (urlString);
				// System.out.println("Processor with url source");
				initializeWithURL();
			}
			catch (MalformedURLException e) { }
		}
		// File Source
		else {
			this.urlString = new java.io.File(urlString);
			// System.out.println("Processor with file source");
			initializeWithFile();
		}
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * set up the processor with a local file as source
	 */
	public void initializeWithFile() {
		try {
			Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, (true));
			myProcessor = Manager.createProcessor(((urlString)).toURI().toURL());
			myProcessor.addControllerListener(this);
		}
		catch (NoPlayerException e) {
			e.printStackTrace();
		}
		catch (MalformedURLException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		myProcessor.configure();
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * set up the processor with an URL as source
	 */
	public void initializeWithURL() {
		try {
			Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, (true));
			myProcessor = Manager.createProcessor(urlSource);
			myProcessor.addControllerListener(this);
		}
		catch (NoPlayerException e) {
			e.printStackTrace();
		}
		catch (MalformedURLException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		myProcessor.configure();
	}

	// Main.fx uses this to get hold of the processor, in order to call start(), stop(), etc.
	public Processor getTheProcessor() {
		return myProcessor;
	}
	
	// gets the visualComponent after it's ready
	public Component getVisualComponent() {
		while(giveVisualComponent == false) { }
		return myProcessor.getVisualComponent();
	}
	
	/**
	 * @author Evelyn Koller 0300033, Michael Kascha 0548800
	 * deals with different types of events from ControllerListener
	 */
	public void controllerUpdate(ControllerEvent event) {
		if (event instanceof ConfigureCompleteEvent) {

			//set content descriptor to null to use processor as player
			myProcessor.setContentDescriptor(null);
			
			// Obtain the track controls.
			TrackControl tc[] = myProcessor.getTrackControls();

			// Search for the track control for the video track.
			TrackControl videoTrack = null;

			for (int i = 0; i < tc.length; i++) {
			    if (tc[i].getFormat() instanceof VideoFormat) {
				videoTrack = tc[i];
				break;
			    }
			}

			// Make a codec chain to apply the effects to the video	
			try {
				myEffect = new MyEffect();
				myBrightness = new MyBrightness();
			    Codec codec[] = { myEffect, myBrightness };
			    videoTrack.setCodecChain(codec);
			} catch (UnsupportedPlugInException e) {
			    System.err.println("Processor doesn't support effects");
			}

			myProcessor.realize();
			while(myProcessor.getState() != myProcessor.Realized) { }
			giveVisualComponent = true;
		}
		
		else if (event instanceof RealizeCompleteEvent) {
			myProcessor.prefetch();
		}
		
		else if (event instanceof PrefetchCompleteEvent) {
		}
		
		//prevent EndOfMediaEvent
		else if(event instanceof EndOfMediaEvent) {
			myProcessor.stop();
			myProcessor.setMediaTime(new Time(0));
			myProcessor.start();
		}
	}

	@Override
	public void dataSinkUpdate(DataSinkEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 *  * @author Evelyn Koller 0300033
	 * setter for accessing setBrightness
	 */
	public void setProcessorBrightness(int value) {
		myBrightness.setBrightness(value);
	}
	
	public void setProcessorEffect(boolean value) {
		myEffect.setEffect(value);
	}
	
	/**
	 * @author Evelyn Koller 0300033
	 * getter for receiving the duration of a video file
	 */
	public double getMediaDuration() {
		return myProcessor.getDuration().getSeconds();
	}

	/**
	 * @author Evelyn Koller 0300033
	 * getter for receiving the actual time of a video file
	 * work in progress
	 */
	public double getMediaTime() {
		//while(giveVisualComponent == false) { }
		return myProcessor.getMediaTime().getSeconds();
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * getter, so the Main.fx save function can give the effect to the saveProcessor
	 */
	public MyEffect getTheEffect() {
		return myEffect;
	}
	
	/**
	 * @author Michael Kascha 0548800
	 * getter, so the Main.fx save function can give the effect to the saveProcessor
	 */
	public MyBrightness getTheBrightness() {
		return myBrightness;
	}
	
}